/*
 * HSM Proxy Project.
 * Copyright (C) 2013 FedICT.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License version
 * 3.0 as published by the Free Software Foundation.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, see 
 * http://www.gnu.org/licenses/.
 */

package be.fedict.hsm.model.security;

import java.util.Arrays;

import javax.ejb.EJB;
import javax.ejb.Stateless;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import be.fedict.hsm.entity.ApplicationEntity;
import be.fedict.hsm.entity.CredentialEntity;

@Stateless
@EJB(name = ApplicationSecurityBean.JNDI_NAME, beanInterface = ApplicationSecurityBean.class)
public class ApplicationSecurityBean {

	private static final Log LOG = LogFactory
			.getLog(ApplicationSecurityBean.class);

	public final static String JNDI_NAME = "java:global/HSMProxyApplicationSecurityBean";

	@PersistenceContext
	private EntityManager entityManager;

	@EJB
	private SecurityAuditGeneratorBean securityAuditGeneratorBean;

	public static ApplicationSecurityBean getInstance() {
		try {
			InitialContext initialContext = new InitialContext();
			return (ApplicationSecurityBean) initialContext.lookup(JNDI_NAME);
		} catch (NamingException e) {
			throw new RuntimeException("JNDI error: " + e.getMessage(), e);
		}
	}

	/**
	 * Authenticates a given credential as a certain application.
	 * 
	 * @param username
	 *            the credential fingerprint.
	 * @param encodedCredential
	 *            the actual credential.
	 * @return the authenticated application identifier.
	 */
	public String getAuthenticatedApplication(String username,
			char[] encodedCredential) {
		LOG.debug("authenticating " + username);
		CredentialEntity credentialEntity = this.entityManager.find(
				CredentialEntity.class, username);
		if (null == credentialEntity) {
			LOG.warn("unknown application credential: " + username);
			this.securityAuditGeneratorBean.webServiceAuthenticationError();
			return null;
		}
		byte[] credential;
		try {
			credential = Hex.decodeHex(encodedCredential);
		} catch (DecoderException e) {
			LOG.error("error decoding credential");
			this.securityAuditGeneratorBean
					.webServiceAuthenticationError(username);
			return null;
		}
		byte[] expectedCredential = credentialEntity.getCredential();
		if (false == Arrays.equals(expectedCredential, credential)) {
			LOG.error("credential mismatch");
			this.securityAuditGeneratorBean
					.webServiceAuthenticationError(username);
			return null;
		}
		LOG.debug("credential matches");
		ApplicationEntity applicationEntity = credentialEntity.getApplication();
		LOG.debug("application id: " + applicationEntity.getId());
		return Long.toString(applicationEntity.getId());
	}
}
